package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Autowired
    private TrackInfoMapper trackInfoMapper;

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private TrackStatMapper trackStatMapper;

    @Autowired
    private VodService vodService;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTrackInfo(TrackInfoVo trackInfoVo, Long userId) {
        //实现声音保存功能,需要将声音信息保存到数据库中
        try {
            TrackInfo trackInfo = new TrackInfo();
            BeanUtils.copyProperties(trackInfoVo, trackInfo);
            trackInfo.setUserId(userId);
            //查询具体专辑信息,通过其声音总数来+1给其声音信息num赋值
            AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
            trackInfo.setOrderNum(albumInfo.getIncludeTrackCount() + 1);
            //	处理流媒体的数据; 时长，类型这些数据页面没有传递；fileId 查询流媒体数据，然后赋值：调用云点播的api;
            TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
            //	赋值：
            trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
            trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());
            trackInfo.setMediaType(trackMediaInfoVo.getType());
            trackInfo.setMediaSize(trackMediaInfoVo.getSize());
            //保存信息表
            trackInfoMapper.insert(trackInfo);

            //保存声音统计表
            saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PLAY);
            saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COLLECT);
            saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PRAISE);
            saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COMMENT);
            //更新专辑信息表里的声音总数
            albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
            //	更新操作;
            albumInfoMapper.updateById(albumInfo);
        } catch (Exception e) {
            log.error("保存声音信息失败！");
            throw new RuntimeException(e);
        }

    }

    @Override
    public IPage<TrackListVo> findUserTrackPage(Page<TrackListVo> page, TrackInfoQuery trackInfoQuery) {
        return trackInfoMapper.selectUserTrackPage(page, trackInfoQuery);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeTrackInfo(Long trackId) {
        //删除三张表的信息，track_info track_stat album_info
        TrackInfo trackInfo = this.getById(trackId);
        //删除第一张表
        trackInfoMapper.deleteById(trackId);
        //删除第二张表
        trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId, trackId));
        //删除第三张表 album_info中的声音总数要做减一操作
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
        //更新
        albumInfoMapper.updateById(albumInfo);
        //需要重写将声音信息表中的order_num字段进行重排序
        trackInfoMapper.updateOrderNum(trackInfo.getAlbumId(), trackInfo.getOrderNum());
        //删除云点播没有用的声音记录
        vodService.deleteMediaFile(trackInfo.getMediaFileId());


    }

    @Override
    public void updateTrackInfo(Long trackId, TrackInfoVo trackInfoVo) {
        //修改时要判断数据是否被修改，如果被修改了，则需要更新
        TrackInfo trackInfo = this.getById(trackId);
        //获取元素音频文件id
        String originmediaFileId = trackInfo.getMediaFileId();
        //属性赋值
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        //判断声音是否被修改
        if (!trackInfoVo.getMediaFileId().equals(originmediaFileId)) {
            //修改了声音
            TrackMediaInfoVo mediaInfo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
            //进行音频文件的信息赋值
            trackInfo.setMediaUrl(mediaInfo.getMediaUrl());
            trackInfo.setMediaDuration(mediaInfo.getDuration());
            trackInfo.setMediaType(mediaInfo.getType());
            trackInfo.setMediaSize(mediaInfo.getSize());
            //删除原有的音频文件
            vodService.deleteMediaFile(originmediaFileId);
        }
        //更新数据
        this.updateById(trackInfo);
    }

    @Override
    public IPage<AlbumTrackListVo> findAlbumTrackPage(Page<AlbumTrackListVo> albumTrackListVoPage, Long albumId, Long userId) {
        /*1、获取到专辑对应的声音列表
         * 2、判断用户是否登录
         * 3、如果用户登录，则查询用户对专辑类型，看是否是VIP免费类型，或者是否是付费类型，从而判断是否显示加锁付费标识
         * 4、如果用户未登录，则只显示对应的专辑所对应的免费集数
         * 5、查找到用户需要付费的声音列表集合，然后判断是否在购买声音的集合中
         * */
        IPage<AlbumTrackListVo> albumTrackListVoIPage = trackInfoMapper.selectAlbumTrackList(albumTrackListVoPage, albumId);
        //查询专辑，用来获取专辑类型：
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        //获取该专辑下的免费试听集数
        Integer tracksForFree = albumInfo.getTracksForFree();
        //判断用户是否登录
        if (null == userId) {
            if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfo.getPayType())) {
                //除免费试听的外都需要付费
                albumTrackListVoIPage.getRecords().stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > tracksForFree).forEach(albumTrackListVo -> albumTrackListVo.setIsShowPaidMark(true));
            }
        } else {
            //用户登录，获取用户信息
            Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfoVo(userId);
            Assert.notNull(userInfoVoResult, "查询用户信息失败");
            UserInfoVo userInfoVo = userInfoVoResult.getData();
            Assert.notNull(userInfoVo, "查询用户信息失败");
            //设置一个变量，记录是否需要付费
            boolean isPaid = false;
            //判断专辑类型VIP免费类型
            if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(albumInfo.getPayType())) {
                //用户不是VIP或者用户是VIP但是已过期，需付费
                if ((userInfoVo.getIsVip() == 1 && userInfoVo.getVipExpireTime().before(new Date())) || userInfoVo.getIsVip() == 0) {
                    isPaid = true;
                } else if (SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(albumInfo.getPayType())) {
                    isPaid = true;
                }

            }
            if (isPaid) {
                //获取专辑下需要付费的列表
                List<AlbumTrackListVo> albumTrackListVoList = albumTrackListVoIPage.getRecords().stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > tracksForFree).collect(Collectors.toList());
                //获取付费声音的id集合
                List<Long> trackIdList = albumTrackListVoList.stream().map(AlbumTrackListVo::getTrackId).collect(Collectors.toList());
                //远程调用，获取用户购买的声音，专辑id存储到map集合中; map.put(trackId,1)-买过; map.put(trackId,0)-未买过;
                Result<Map<Long, Integer>> mapResult = userInfoFeignClient.userIsPaidTrack(albumId, trackIdList);
                Assert.notNull(mapResult, "查询用户购买声音失败");
                Map<Long, Integer> map = mapResult.getData();
                for (AlbumTrackListVo albumTrackListVo : albumTrackListVoList) {
                    albumTrackListVo.setIsShowPaidMark(map.get(albumTrackListVo.getTrackId()) == 0);
                }
            }
        }
        return albumTrackListVoIPage;
    }

    @Override
    public void updateTrackStat(TrackStatMqVo trackStatMqVo) {
        //  判断是否是属于播放量：
        if (SystemConstant.TRACK_STAT_PLAY.equals(trackStatMqVo.getStatType())) {
            //  调用更新方法;
            trackInfoMapper.updateTrackStat(trackStatMqVo.getCount(), trackStatMqVo.getTrackId(), trackStatMqVo.getStatType());
            //  2.  更新专辑播放量；
            albumInfoMapper.updateAlbumStat(trackStatMqVo.getCount(), trackStatMqVo.getAlbumId(), SystemConstant.ALBUM_STAT_PLAY);
        } else if (SystemConstant.TRACK_STAT_COLLECT.equals(trackStatMqVo.getStatType())) {
            //  暂无，后续有其他类似功能可扩展
        }
    }

    @Override
    public List<TrackInfo> findPaidTrackInfoList(Long trackId, Integer trackCount, Long userId) {
        //在订单结算页只能显示一个专辑下的声音，固要根据专辑id、userid查询
        List<TrackInfo> trackInfoList = new ArrayList<>();
        //根据声音id查询声音信息再查询到专辑信息
        TrackInfo trackInfo = this.getById(trackId);
        Result<List<Long>> userPaidTrackList = userInfoFeignClient.findUserPaidTrackList(trackInfo.getAlbumId());
        //  判断返回数据集
        Assert.notNull(userPaidTrackList, "查询用户购买声音列表失败");
        List<Long> userPaidTrackIdList = userPaidTrackList.getData();
        //判断当前购买的集数
        if (trackCount == 0) {
            //购买的是本集
            trackInfoList.add(trackInfo);
        } else {
            //购买的是多集
            LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
            wrapper.gt(TrackInfo::getOrderNum, trackInfo.getOrderNum())
                    .eq(TrackInfo::getAlbumId, trackInfo.getAlbumId());
            if (!CollectionUtils.isEmpty(userPaidTrackIdList)) {
                //排除已购买的
                wrapper.notIn(TrackInfo::getId, userPaidTrackIdList);
            }
            wrapper.last("limit " + trackCount);
            //查询数据
            trackInfoList = trackInfoMapper.selectList(wrapper);
        }
        return trackInfoList;
    }

    @Override
    public List<Map<String, Object>> findUserTrackPaidList(Long trackId, Long userId) {
         /*
        1.  从当前点击的声音开始，计算有多少需要付费的声音列表;
        2.  查询用户是否购买过当前专辑对应的声音，然后与1步骤进行过滤;
         */
        List<Map<String, Object>> list = new ArrayList<>();
        //  获取对象
        TrackInfo trackInfo = this.getById(trackId);
        //  获取当前声音Id的排序值;
        Integer orderNum = trackInfo.getOrderNum();
        //  获取到当前用户购买的声音列表；
        Result<List<Long>> trackIdListResult = userInfoFeignClient.findUserPaidTrackList(trackInfo.getAlbumId());
        Assert.notNull(trackIdListResult, "查询用户购买声音列表失败");
        List<Long> trackIdList = trackIdListResult.getData();

        //  从当前声音Id开始计算有多少声音是需要付费的集合Id;
        //  select * from track_info where order_num > 8 and album_id = 341;
        //  7--54  trackIdListResult {17,18,19}
        List<TrackInfo> trackInfoList = trackInfoMapper.selectList(new LambdaQueryWrapper<TrackInfo>()
                .eq(TrackInfo::getAlbumId, trackInfo.getAlbumId())
                .gt(TrackInfo::getOrderNum, orderNum));

        //  两个集合取差集,需要付费的声音列表;
        List<TrackInfo> paidTrackIdList = trackInfoList.stream().filter(trackInfoItem -> !trackIdList.contains(trackInfoItem.getId())).collect(Collectors.toList());
        //  根据专辑Id获取专辑对象
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
        //  判断
        if (paidTrackIdList.size() >= 0) {
            //  显示本集;
            HashMap<String, Object> map = new HashMap<>();
            map.put("name", "本集");
            //  当前每一集声音的钱数;
            map.put("price", albumInfo.getPrice());
            map.put("trackCount", 0);
            //  添加本集到集合;
            list.add(map);
        }
        //  后9集
        if (paidTrackIdList.size() > 0 && paidTrackIdList.size() <= 10) {
            //  显示后size集;
            HashMap<String, Object> map = new HashMap<>();
            map.put("name", "后" + paidTrackIdList.size() + "集");
            //  当前每一集声音的钱数;
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal(String.valueOf(paidTrackIdList.size()))));
            map.put("trackCount", paidTrackIdList.size());
            //  添加本集到集合;
            list.add(map);
        }
        //  后10集;
        if (paidTrackIdList.size() > 10) {
            //  后10集合;
            HashMap<String, Object> map = new HashMap<>();
            map.put("name", "后10集");
            //  当前每一集声音的钱数;
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal("10")));
            map.put("trackCount", 10);
            //  添加本集到集合;
            list.add(map);
        }

        //  后19集
        if (paidTrackIdList.size() > 10 && paidTrackIdList.size() <= 20) {
            //  显示后size集;
            HashMap<String, Object> map = new HashMap<>();
            map.put("name", "后" + paidTrackIdList.size() + "集");
            //  当前每一集声音的钱数;
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal(String.valueOf(paidTrackIdList.size()))));
            map.put("trackCount", paidTrackIdList.size());
            //  添加本集到集合;
            list.add(map);
        }
        //  后所有集;
        if (paidTrackIdList.size() > 20) {
            //  后10集合;
            HashMap<String, Object> map = new HashMap<>();
            map.put("name", "后20集");
            //  当前每一集声音的钱数;
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal("20")));
            map.put("trackCount", 20);
            //  添加本集到集合;
            list.add(map);
        }
        //  返回数据
        return list;
    }


    public void saveTrackStat(Long trackId, String statPlay) {
        //保存声音统计表
        TrackStat trackStat = new TrackStat();
        //赋值
        trackStat.setTrackId(trackId);
        trackStat.setStatType(statPlay);
        trackStat.setStatNum(new Random().nextInt(1000));
        trackStatMapper.insert(trackStat);
    }
}
